package com.stm.bi.report.productTrend;

import com.stm.base.dto.vo.DictVO;
import com.stm.base.provider.DictionaryProvider;
import com.stm.bi.constant.ReportConstants;
import com.stm.bi.core.util.DateUtils;
import com.stm.bi.core.util.ETLUtils;
import com.stm.bi.core.util.SqlUtils;
import com.stm.bi.dto.query.*;
import com.stm.bi.enums.ParamType;
import com.stm.bi.model.Chart;
import com.stm.bi.model.DatatablePage;
import com.stm.bi.model.Title;
import com.stm.bi.repository.ods.OdsWarehouseRepository;
import com.stm.framework.core.util.StringUtil;
import com.stm.framework.dbcp.JdbcService;
import com.stm.framework.dto.Response;
import com.stm.saas.api.*;
import com.stm.saas.dto.query.ProductStylePageQry;
import com.stm.saas.dto.vo.ProductStyleQueryVO;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

import static com.stm.bi.constant.DictionaryConstants.PARAMS_CONFIG;
import static com.stm.bi.constant.GroupTypeConstants.SUM;
import static com.stm.bi.constant.IndexConstants.*;
import static com.stm.bi.report.productTrend.ProductDataQueryExe.DELAY;

@Component
public class StyleStructureReportQueryExe {

    @Resource
    private JdbcService jdbcService;
    @Resource
    private IndexRemoteService indexRemoteService;
    @Resource
    private ProductCategoryRemoteService productCategoryRemoteService;
    @Resource
    private ProductAssortmentRemoteService productAssortmentRemoteService;
    @Resource
    private ProductStyleRemoteService productStyleRemoteService;

    @Resource
    private ProductStyleDetailRemoteService productStyleDetailRemoteService;

    @Resource
    private DictionaryProvider dictionaryProvider;
    @Resource
    private OdsWarehouseRepository odsWarehouseRepository;


    public Chart<List<List<Object>>> styleStructureChart(ChartReportQry reportQry) {
        String seasonParam = reportQry.getParams().stream().filter(item -> ParamType.SEASON.getValue().equals(item.getType())).findFirst().map(ParamQry::getCode).orElse(null);

        Chart<List<List<Object>>> chart = new Chart<>();
        List<List<Object>> datas = new ArrayList<>();
        List<List<Object>> total = new ArrayList<>();

        List<GroupField> groupFields = List.of(new GroupField().setFieldName(QTY_FIELD).setGroupType(SUM));

        List<String> dateList = DateUtils.getHistoryDateList(reportQry.getStartDate(), reportQry.getEndDate(), reportQry.getDateType().getValue(), DELAY);
        if(dateList.isEmpty()){
            return chart;
        }
        String startDate = dateList.getFirst();
        String endDate = dateList.getLast();

        DimensionDataGroupQry qry = new DimensionDataGroupQry()
                .setSalesType(reportQry.getSalesType())
                .setGroupFields(groupFields)
                .setGroupBy(Arrays.asList(DATE_FIELD, PROD_SEASON_FIELD))
                .setDateType(reportQry.getDateType().getValue())
                .setDeptId(reportQry.getDeptId())
                .setStartDate(startDate)
                .setEndDate(endDate);

        if (StringUtil.isNotEmpty(seasonParam)) {
            Map<String, Object> otherConditions = new HashMap<>();
            List<String> codes = new ArrayList<>();
            Response<List<ProductStyleQueryVO>> res = productStyleRemoteService.selectList(new ProductStylePageQry().setSeason(seasonParam));
            if (!res.isSuccess()) {
                return chart;
            }
            codes.addAll(res.get().stream().map(ProductStyleQueryVO::getCode).toList());
            otherConditions.put(STYLE_CODE_FIELD, codes);
            qry.setOtherConditions(otherConditions);
        }
        List<DictVO> dicts = dictionaryProvider.selectList(PARAMS_CONFIG);
        List<DictVO> prodSeason = dicts.stream().filter(dict -> ReportConstants.VALUE_OUT_OF_SEASON.equals(dict.getValue())).findFirst().orElse(null).getChildren();
        // 添加数据项
        for (DictVO dict : prodSeason) {
            chart.getItems().add(dict.getLabel());
        }

        String sql = SqlUtils.buildSql(qry, "ads_base_product_multi_sales");
        // es查询数据
        List<Map> orginalData = jdbcService.selectList(sql, new Object[]{});
        // 匹配不到字典值全部按当季处理
        orginalData.stream().filter(e -> Objects.equals(e.get(PROD_SEASON_FIELD), "-99") || Objects.isNull(e.get(PROD_SEASON_FIELD))).forEach(e -> {
            e.put(PROD_SEASON_FIELD, ReportConstants.VALUE_SEASON);
        });
        // 获取日期列表

        //合计销量&占比
        double seasonSum = 0;
        double outSeasonOneYearSum = 0;
        double outSeasonTwoYearSum = 0;
        double outSeasonThreeYearSum = 0;
        double outSeasonMoreYearSum = 0;
        String seasonRatio = "";
        String outSeasonOneYearRatio = "";
        String outSeasonTwoYearRatio = "";
        String outSeasonThreeYearRatio = "";
        String outSeasonMoreYearRatio = "";

        for(String date : dateList){
            List<Object> row = new ArrayList<>();
            row.add(DateUtils.getReportDateName(date, reportQry.getDateType().getValue()));

            List<Map> maps = orginalData.stream()
                    .filter(d -> date.equals(d.get(DATE_FIELD)))
                    .toList();
            // 遍历过季字典赋值
            for (DictVO dict : prodSeason) {
                double sum = maps.stream()
                        .filter(Objects::nonNull)
                        .filter(e -> Objects.equals(e.get(PROD_SEASON_FIELD), dict.getValue()))
                        .map(d -> (BigDecimal) d.get(QTY_FIELD))
                        .filter(Objects::nonNull)
                        .mapToDouble(BigDecimal::doubleValue)
                        .sum();
                if(ReportConstants.VALUE_SEASON.equals(dict.getValue())){
                    seasonSum += sum;
                }else if(ReportConstants.VALUE_OUT_SEASON_1_YEAR.equals(dict.getValue())){
                    outSeasonOneYearSum += sum;
                }else if(ReportConstants.VALUE_OUT_SEASON_2_YEAR.equals(dict.getValue())){
                    outSeasonTwoYearSum += sum;
                }else if(ReportConstants.VALUE_OUT_SEASON_3_YEAR.equals(dict.getValue())){
                    outSeasonThreeYearSum += sum;
                }else if(ReportConstants.VALUE_OUT_SEASON_MORE_YEAR.equals(dict.getValue())){
                    outSeasonMoreYearSum += sum;
                }
                row.add(BigDecimal.valueOf(sum));
            }
            datas.add(row);
        }
        // 计算合计和占比
        double totalSum = seasonSum + outSeasonOneYearSum + outSeasonTwoYearSum + outSeasonThreeYearSum + outSeasonMoreYearSum;
        if(totalSum > 0){
            seasonRatio = BigDecimal.valueOf(seasonSum / totalSum * 100).setScale(2, RoundingMode.HALF_UP) + "%";
            outSeasonOneYearRatio = BigDecimal.valueOf(outSeasonOneYearSum / totalSum * 100).setScale(2, RoundingMode.HALF_UP) + "%";
            outSeasonTwoYearRatio = BigDecimal.valueOf(outSeasonTwoYearSum / totalSum * 100).setScale(2, RoundingMode.HALF_UP) + "%";
            outSeasonThreeYearRatio = BigDecimal.valueOf(outSeasonThreeYearSum / totalSum * 100).setScale(2, RoundingMode.HALF_UP) + "%";
            outSeasonMoreYearRatio = BigDecimal.valueOf(outSeasonMoreYearSum / totalSum * 100).setScale(2, RoundingMode.HALF_UP) + "%";
        }else{
            seasonRatio = "0%";
            outSeasonOneYearRatio = "0%";
            outSeasonTwoYearRatio = "0%";
            outSeasonThreeYearRatio = "0%";
            outSeasonMoreYearRatio = "0%";
        }
        total.add(Arrays.asList(ReportConstants.LABEL_SEASON,BigDecimal.valueOf(seasonSum),seasonRatio,ReportConstants.STRING_ZERO));
        total.add(Arrays.asList(ReportConstants.LABEL_OUT_SEASON_1_YEAR,BigDecimal.valueOf(outSeasonOneYearSum),outSeasonOneYearRatio,ReportConstants.STRING_ZERO));
        total.add(Arrays.asList(ReportConstants.LABEL_OUT_SEASON_2_YEAR,BigDecimal.valueOf(outSeasonTwoYearSum),outSeasonTwoYearRatio,ReportConstants.STRING_ZERO));
        total.add(Arrays.asList(ReportConstants.LABEL_OUT_SEASON_3_YEAR,BigDecimal.valueOf(outSeasonThreeYearSum),outSeasonThreeYearRatio,ReportConstants.STRING_ZERO));
        total.add(Arrays.asList(ReportConstants.LABEL_OUT_SEASON_MORE_YEAR,BigDecimal.valueOf(outSeasonMoreYearSum),outSeasonMoreYearRatio,ReportConstants.STRING_ZERO));

        chart.setDatas(datas);
        chart.setExtend(total);

        return chart;
    }

    public Chart<List<List<Object>>> styleStructureDetailChart(DetailChartReportQry reportQry) {
        String prodType = reportQry.getParams().stream().filter(item -> ParamType.OUT_SEASON.getValue().equals(item.getType())).findFirst().map(ParamQry::getCode).orElse(null);
        String seasonParam = reportQry.getParams().stream().filter(item -> ParamType.SEASON.getValue().equals(item.getType())).findFirst().map(ParamQry::getCode).orElse(null);

        Chart<List<List<Object>>> chart = new Chart<>();
        String dateType = reportQry.getDateType().getValue();
        List<String> dateList = DateUtils.getHistoryDateList(reportQry.getStartDate(), reportQry.getEndDate(), reportQry.getDateType().getValue(), DELAY);

        if(dateList.isEmpty()){
            return chart;
        }
        String startDate = dateList.getFirst();
        String endDate = dateList.getLast();

        List<GroupField> groupFields = new ArrayList<>(Collections.singletonList(
                new GroupField().setFieldName(QTY_FIELD).setGroupType(ReportConstants.STRING_SUM)
        ));

        List<String> groupBy = new ArrayList<>(Arrays.asList(STYLE_CODE_FIELD, STYLE_NAME_FIELD, PROD_SEASON_FIELD));

        DimensionDataGroupQry qry = new DimensionDataGroupQry()
                .setSalesType(reportQry.getSalesType())
                .setDateType(reportQry.getDateType().getValue())
                .setStartDate(startDate)
                .setEndDate(endDate)
                .setGroupFields(groupFields)
                .setDeptId(reportQry.getDeptId())
                .setGroupBy(groupBy);

        // 款式过滤
        if (StringUtil.isNotEmpty(seasonParam)) {
            List<String> codes = new ArrayList<>();
            Response<List<ProductStyleQueryVO>> res = productStyleRemoteService.selectList(new ProductStylePageQry().setSeason(seasonParam));
            if (!res.isSuccess()) {
                return chart;
            }
            codes.addAll(res.get().stream().map(ProductStyleQueryVO::getCode).toList());
            Map<String, Object> map = new HashMap<>();
            map.put(STYLE_CODE_FIELD, codes);
            qry.setOtherConditions(map);
        }

        List<DictVO> dicts = dictionaryProvider.selectList(PARAMS_CONFIG);
        List<DictVO> prodSeason = dicts.stream().filter(dict -> ReportConstants.VALUE_OUT_OF_SEASON.equals(dict.getValue())).findFirst().orElse(null).getChildren();
        // es数据查询
        List<Map> allData = new ArrayList<>();

        String sql = SqlUtils.buildSql(qry, "ads_base_product_multi_sales");
        List<Map> data = jdbcService.selectList(sql, new Object[]{});
        // 匹配不到字典值全部按当季处理
        if (prodType != null) {
            if (prodType.isEmpty()){
                // 全部
                allData.addAll(data);
            }else if (prodType.equals(ReportConstants.VALUE_SEASON)){
                // 当季和其他都按当季处理
                allData.addAll(data.stream().filter(e -> e.get(PROD_SEASON_FIELD).equals("-99")).toList());
                allData.addAll(data.stream().filter(e -> e.get(PROD_SEASON_FIELD).equals(ReportConstants.VALUE_SEASON)).toList());
            }else{
                // 其他过应季
                for (DictVO dict : prodSeason) {
                    if (dict.getValue().equals(prodType)) {
                        allData.addAll(data.stream().filter(e -> e.get(PROD_SEASON_FIELD).equals(dict.getValue())).toList());
                    }
                }
            }

        }

        if (reportQry.getLimit() > 0) {
            allData.sort(Comparator.comparing((Map m) -> (BigDecimal) m.get(QTY_FIELD)).reversed());
        } else {
            allData.sort(Comparator.comparing((Map m) -> (BigDecimal) m.get(QTY_FIELD)));
        }

        List<Map> finalMaps = allData.subList(0, Math.min(allData.size(), Math.abs(reportQry.getLimit())));

        List<String> codes = finalMaps.stream()
                .map(m ->(String) m.get(STYLE_CODE_FIELD))
                .toList();

        groupBy.add(DATE_FIELD);
        qry.setGroupBy(groupBy);
        Map<String, Object> other = qry.getOtherConditions() == null ? new HashMap<>() : qry.getOtherConditions();
        other.put(STYLE_CODE_FIELD, codes);
        qry.setOtherConditions(other);
        // es查询数据
        List<Map> finalDataMap = new ArrayList<>();

        String dataSql = SqlUtils.buildSql(qry, "ads_base_product_multi_sales");
        List<Map> dataMap = jdbcService.selectList(dataSql, new Object[]{});

        // 匹配不到字典值全部按当季处理
        if (prodType != null) {
            if (prodType.isEmpty()){
                // 全部
                finalDataMap.addAll(dataMap);
            }else if (prodType.equals(ReportConstants.VALUE_SEASON)){
                // 当季和其他都按当季处理
                finalDataMap.addAll(dataMap.stream().filter(e -> e.get(PROD_SEASON_FIELD).equals("-99")).toList());
                finalDataMap.addAll(dataMap.stream().filter(e -> e.get(PROD_SEASON_FIELD).equals(ReportConstants.VALUE_SEASON)).toList());
            }else{
                // 其他过应季
                for (DictVO dict : prodSeason) {
                    if (dict.getValue().equals(prodType)) {
                        finalDataMap.addAll(dataMap.stream().filter(e -> e.get(PROD_SEASON_FIELD).equals(dict.getValue())).toList());
                    }
                }
            }

        }

        List<List<Object>> total = new ArrayList<>();
        List<List<Object>> datas = new ArrayList<>();

        BigDecimal sum = finalMaps.stream()
                .map(m -> (BigDecimal) m.get(QTY_FIELD))
                .filter(Objects::nonNull)
                .reduce(BigDecimal.ZERO, BigDecimal::add);

        for (Map map : finalMaps) {
            String ratio = "0.00%";
            BigDecimal qty =(BigDecimal) map.get(QTY_FIELD);
            if (qty != null && sum.compareTo(BigDecimal.ZERO) != 0) {
                ratio = qty.divide(sum, 4, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)).setScale(2, RoundingMode.HALF_UP) + "%";
            }
            total.add(Arrays.asList(map.get(STYLE_NAME_FIELD), qty, ratio,ReportConstants.STRING_ZERO));
            chart.getItems().add((String) map.get(STYLE_NAME_FIELD));
        }


        for (String date : dateList) {
            List<Object> row = new ArrayList<>();

            row.add(DateUtils.getReportDateName(date, reportQry.getDateType().getValue()));
            for (Map map : finalMaps) {

                Map finalData = finalDataMap.stream()
                        .filter(m -> Objects.equals(m.get(STYLE_CODE_FIELD), map.get(STYLE_CODE_FIELD)))
                        .filter(m -> Objects.equals(m.get(DATE_FIELD), date))
                        .findAny().orElse(new HashMap());

                row.add(finalData.get(QTY_FIELD) == null ? 0 : finalData.get(QTY_FIELD));
            }
            datas.add(row);
        }

        chart.setDatas(datas);
        chart.setExtend(total);

        return chart;
    }

    public DatatablePage styleStructureTable(TableReportQry reportQry) {
        String prodType = reportQry.getParams().stream().filter(item -> ParamType.OUT_SEASON.getValue().equals(item.getType())).findFirst().map(ParamQry::getCode).orElse(null);
        String seasonParam = reportQry.getParams().stream().filter(item -> ParamType.SEASON.getValue().equals(item.getType())).findFirst().map(ParamQry::getCode).orElse(null);

        DatatablePage table = new DatatablePage();
        List<Map<String, String>> datas = new ArrayList<>();

        //页数页码
        int pageNum = reportQry.getPageNum();
        int pageSize = reportQry.getPageSize();

        Map<String, Object> other = new HashMap<>();
        if (prodType != null && !prodType.isEmpty()) {
            other.put(PROD_SEASON_FIELD, prodType);
        }

        List<GroupField> groupFields = new ArrayList<>(Collections.singletonList(
                new GroupField().setFieldName(QTY_FIELD).setGroupType(ReportConstants.STRING_SUM)
        ));

        List<String> groupBy = new ArrayList<>(Arrays.asList(STYLE_CODE_FIELD, STYLE_NAME_FIELD, PROD_SEASON_FIELD));
        List<String> dateList = DateUtils.getHistoryDateList(reportQry.getStartDate(), reportQry.getEndDate(), reportQry.getDateType().getValue(), DELAY);

        if(dateList.isEmpty()){
            return table;
        }
        String startDate = dateList.getFirst();
        String endDate = dateList.getLast();

        DimensionDataGroupQry qry = new DimensionDataGroupQry()
                .setSalesType(reportQry.getSalesType())
                .setDateType(reportQry.getDateType().getValue())
                .setDeptId(reportQry.getDeptId())
                .setGroupFields(groupFields)
                .setGroupBy(groupBy)
                .setStartDate(startDate)
                .setEndDate(endDate);

        // 款式过滤
        if (StringUtil.isNotEmpty(seasonParam)) {
            List<String> codes = new ArrayList<>();
            Response<List<ProductStyleQueryVO>> res = productStyleRemoteService.selectList(new ProductStylePageQry().setSeason(seasonParam));
            if (!res.isSuccess()) {
                return table;
            }
            codes.addAll(res.get().stream().map(ProductStyleQueryVO::getCode).toList());
            other.put(STYLE_CODE_FIELD, codes);
        }
        qry.setOtherConditions(other);


        List<Title> titles = new ArrayList<>();
        titles.add(new Title().setName(ReportConstants.STRING_STYLE_NAME).setCode(ReportConstants.STRING_NAME));
        titles.addAll(ETLUtils.getTitles(dateList, reportQry.getDateType().getValue()));
        titles.add(new Title().setName(ReportConstants.STRING_QTY_TOTAL).setCode(ReportConstants.STRING_SUM));

        String totalSql = SqlUtils.buildSql(qry, "ads_base_product_multi_sales");;
        // 统计所有数据合计值
        List<Map> res = jdbcService.selectList(totalSql, new Object[]{});
        Map<String, String> sums = new HashMap<>();

        // 统计页数内数据
        List<Map> finalMaps;
        // 根据销量排序
        res.sort(Comparator.comparing((Map m) -> (BigDecimal) m.get(QTY_FIELD)).reversed());

        if (pageNum == 1) {
            finalMaps = res.subList(0, Math.min(res.size(), pageSize - 1));
            sums.put(ReportConstants.STRING_NAME,ReportConstants.STRING_TOTAL);
        } else {
            finalMaps = res.subList(
                    Math.min(res.size(), (pageNum - 1) * pageSize  - 1),
                    Math.min(res.size(), pageNum * pageSize  - 1)
            );
        }

        List<String> codes = finalMaps.stream()
                .map(m -> (String) m.get(STYLE_CODE_FIELD))
                .collect(Collectors.toList());

        // 统计分页第一页的合计值
        qry.setGroupBy(Arrays.asList(DATE_FIELD,PROD_SEASON_FIELD));

        String sql = SqlUtils.buildSql(qry, "ads_base_product_multi_sales");
        List<Map> countMap = jdbcService.selectList(sql, new Object[]{});
        BigDecimal qtyTotal = BigDecimal.ZERO;
        if (pageNum == 1) {
            for (String date : dateList) {
                BigDecimal sum = countMap.stream()
                        .filter(Objects::nonNull)
                        .filter(e -> e.get(DATE_FIELD).equals(date))
                        .map(m -> (BigDecimal) m.get(QTY_FIELD))
                        .reduce(BigDecimal.ZERO, BigDecimal::add);
                sums.put(date, sum.setScale(2, RoundingMode.HALF_UP).toString());
                qtyTotal = qtyTotal.add(sum);
            }
            sums.put(ReportConstants.STRING_SUM, qtyTotal.setScale(2, RoundingMode.HALF_UP).toString());
            datas.add(sums);
        }

        groupBy.add(DATE_FIELD);
        qry.setGroupBy(groupBy)
                .setGroupFields(null);
        qry.getOtherConditions().put(STYLE_CODE_FIELD, codes);

        String dataSql = SqlUtils.buildSql(qry, "ads_base_product_multi_sales");
        List<Map> dataMap = jdbcService.selectList(dataSql, new Object[]{});

        for (Map finalMap : finalMaps) {
            qtyTotal = BigDecimal.ZERO;
            Map<String, String> maps = new HashMap<>();
            maps.put(ReportConstants.STRING_NAME, (String) finalMap.get(STYLE_NAME_FIELD));
            for (String date : dateList) {
                BigDecimal sum = dataMap.stream()
                        .filter(Objects::nonNull)
                        .filter(e -> e.get(DATE_FIELD).equals(date))
                        .filter(e -> e.get(STYLE_CODE_FIELD).equals(finalMap.get(STYLE_CODE_FIELD)))
                        .map(m -> (BigDecimal) m.get(QTY_FIELD))
                        .reduce(BigDecimal.ZERO, BigDecimal::add);
                maps.put(date, sum.setScale(2, RoundingMode.HALF_UP).toString());
                qtyTotal = qtyTotal.add(sum);
            }
            maps.put(ReportConstants.STRING_SUM, qtyTotal.setScale(2, RoundingMode.HALF_UP).toString());
            datas.add(maps);
        }
        table.setTotal(res.size());
        table.setDatas(datas);
        table.setTitles(titles);
        table.setSize(pageSize);
        table.setCurrent(pageNum);

        return table;
    }


}
